﻿using System;
using System.Net.Sockets;
using System.Net;

namespace Kugar.Core.Communications.Transfer
{
    public static class SocketManager
    {
        private static TCPTransferFactory tcpFactory = null;
        private static UDPFactory udpFactory = null;
        private static RUDPFactory rudpFactory = null;
        private static SerialPortTransferFactory serialPortFactory = null;

        static SocketManager()
        {
            tcpFactory = new TCPTransferFactory();
            udpFactory = new UDPFactory();

            tcpFactory.ConnectRequest += OnConnectRequest;
            tcpFactory.ConnectSuccessed += OnConnectSuccessed;

            udpFactory.ConnectRequest += OnConnectRequest;
            udpFactory.ConnectSuccessed += OnConnectSuccessed;
        }

        public static void ListenPort(TransferConnectConfig listenConfig)
        {
            switch (listenConfig.Protocol)
            {
                case TransferProtocolType.TCP_Normal:
                    var tcpConfig = (SocketManager_ListenTCPPortConfig)listenConfig;
                    tcpFactory.AddPort(tcpConfig.Port, tcpConfig.EnableSpliteBag, tcpConfig.MaxDataLengthPerDataPack);
                    break;
                
                case TransferProtocolType.UDP_Normal:
                    //var udpConfig = (SocketManager_ListenUDPPortConfig)listenConfig;
                    udpFactory.Listen(listenConfig);
                    break;
            }
        }

        public static ITransfer ConnectTo(TransferConnectConfig connectRemoteConfig)
        {
            switch (connectRemoteConfig.Protocol)
            {
                case TransferProtocolType.TCP_Normal:
                    //var tcpConfig = (SocketManager_TcpConnectRemoteConfig) connectRemoteConfig;
                    return tcpFactory.ConnectTo(tcpConfig.LocalPort, tcpConfig.RemotePoint, tcpConfig.EnableSpliteBag, tcpConfig.MaxDataLengthPerDataPack);
                case TransferProtocolType.UDP_Normal:
                    //if (connectRemoteConfig is ScoketManager_UDPConnectBorcastConfig)
                    //{
                    //    var udpConfig = (ScoketManager_UDPConnectBorcastConfig)connectRemoteConfig;
                    //    return udpFactory.ConnectToBroadcast(udpConfig.LocalPort, udpConfig.BorcastPort, udpConfig.MaxDataLengthPerDataPack);                        
                    //}
                    //else
                    //{
                        //var udpConfig = (SocketManager_UdpConnectRemoteConfig) connectRemoteConfig;
                    return udpFactory.ConnectTo(connectRemoteConfig);
                    //}
                case TransferProtocolType.UDP_RUDP:
                    {
                        //return rudpFactory.BeginConnectTo()
                    }
                    break;
            }

            return null;
        }

        public static ITransfer TcpConnectTo(int localPort, IPEndPoint remotePoint, bool enableSplitePack, int MaxDatamaxLengthPerDataPack)
        {
            //switch (protocolType)
            //{
            //        case ProtocolType.Tcp:
            return tcpFactory.ConnectTo(localPort, remotePoint, enableSplitePack, MaxDatamaxLengthPerDataPack);
            //}
        }

        public static ITransfer UdpConnectTo(int localPort, IPEndPoint remotePoint, bool enableSendCheck, int MaxDatamaxLengthPerDataPack)
        {
            return udpFactory.ConnectTo(localPort, remotePoint, enableSendCheck, MaxDatamaxLengthPerDataPack);
        }

        public static void Close()
        {
            tcpFactory.ConnectRequest -= OnConnectRequest;
            tcpFactory.ConnectSuccessed -= OnConnectSuccessed;

            udpFactory.ConnectRequest -= OnConnectRequest;
            udpFactory.ConnectSuccessed -= OnConnectSuccessed;

            tcpFactory.Close();
            udpFactory.Close();


        }

        /// <summary>
        ///     当有远程TCP申请链接时
        /// </summary>
        public static event EventHandler<RemoteRequestConnectEventArgs> ConnectRequest;

        /// <summary>
        ///     当成功连接后引发该事件
        /// </summary>
        public static event EventHandler<RemoteConenctSuccessEventArgs> ConnectSuccessed;


        private static void OnConnectRequest(object sender, RemoteRequestConnectEventArgs e)
        {
            Events.EventHelper.Raise(ConnectRequest, sender, e);
        }

        private static void OnConnectSuccessed(object sender, RemoteConenctSuccessEventArgs e)
        {
            Events.EventHelper.Raise(ConnectSuccessed, sender, e);
        }


    }

    #region "连接远程目标配置"

    public interface ISocketManager_ConnectRemoteConfig
    {

        TransferProtocolType Protocol { get; }
        int MaxDataLengthPerDataPack { set; get; }

    }

    public abstract class SocketManager_ConnectRemoteConfigBase : ISocketManager_ConnectRemoteConfig
    {
        #region Implementation of ISocketManager_ConnectRemoteConfig

        public abstract TransferProtocolType Protocol { get; }

        public int MaxDataLengthPerDataPack { get; set; }

        #endregion
    }

    public class SocketManager_TcpConnectRemoteConfig : SocketManager_ConnectRemoteConfigBase
    {
        public SocketManager_TcpConnectRemoteConfig()
        {
            base.MaxDataLengthPerDataPack = 2048;
            LocalPort = 0;
            EnableSpliteBag = false;
        }

        public int LocalPort { get; set; }
        public IPEndPoint RemotePoint { set; get; }
        public bool EnableSpliteBag { set; get; }

        #region Implementation of ISocketManager_ConnectRemoteConfig

        public override TransferProtocolType Protocol
        {
            get { return TransferProtocolType.TCP_Normal; }

        }

        #endregion
    }

    public class SocketManager_UdpConnectRemoteConfig : SocketManager_ConnectRemoteConfigBase
    {
        public SocketManager_UdpConnectRemoteConfig()
        {
            base.MaxDataLengthPerDataPack = 2048;
            LocalPort = 0;
            EnableSendCheck = false;
        }

        public int LocalPort { get; set; }
        public IPEndPoint RemotePoint { set; get; }
        public bool EnableSendCheck { set; get; }

        #region Implementation of ISocketManager_ConnectRemoteConfig

        public override TransferProtocolType Protocol
        {
            get { return TransferProtocolType.; }

        }

        #endregion
    }

    public class ScoketManager_UDPConnectBorcastConfig:SocketManager_ConnectRemoteConfigBase
    {

        public int BorcastPort { set; get; }

        public int LocalPort { set; get; }

        #region Overrides of SocketManager_ConnectRemoteConfigBase

        public override TransferProtocolType Protocol
        {
            get { return TransferProtocolType.UDP; }
        }

        

        #endregion
    }

    #endregion

    #region "用于监听本地连接端口的配置"

    public interface ISocketManager_ListenPortConfig
    {

        TransferProtocolType Protocol { get; }
        int MaxDataLengthPerDataPack { set; get; }
    }

    public class SocketManager_ListenUDPPortConfig : ISocketManager_ListenPortConfig
    {
        public SocketManager_ListenUDPPortConfig()
        {
            MaxDataLengthPerDataPack = 2048;
        }

        #region Implementation of ISocketManager_ListenPortConfig

        public int Port { get; set; }

        public TransferProtocolType Protocol
        {
            get { return TransferProtocolType.UDP; }
        }

        private int _maxDatamaxLengthPerDataPack = 1024;
        public int MaxDataLengthPerDataPack
        {
            get { return _maxDatamaxLengthPerDataPack; }
            set
            {
                if (value <= 1024)
                {
                    throw new ArgumentOutOfRangeException("value");
                }

                _maxDatamaxLengthPerDataPack = value;
            }
        }

        #endregion

        public bool EnableSendCheck { set; get; }
        //public byte[] HeaderData { set; get; }
    }

    public class SocketManager_ListenTCPPortConfig : ISocketManager_ListenPortConfig
    {
        public SocketManager_ListenTCPPortConfig()
        {
            MaxDataLengthPerDataPack = 2048;
        }

        #region Implementation of ISocketManager_ListenPortConfig

        public int Port { get; set; }

        public TransferProtocolType Protocol
        {
            get { return TransferProtocolType.TCP_Normal; }
        }

        private int _maxDatamaxLengthPerDataPack = 1024;
        public int MaxDataLengthPerDataPack
        {
            get { return _maxDatamaxLengthPerDataPack; }
            set
            {
                if (value <= 1024)
                {
                    throw new ArgumentOutOfRangeException("value");
                }

                _maxDatamaxLengthPerDataPack = value;
            }
        }

        #endregion

        public bool EnableSpliteBag { set; get; }
        public byte[] HeaderData { set; get; }
    }

    #endregion
}
